Sears Kit Home Locations Using Folium Maps

M. Fawcett - 11/30/2021

This Notebook builds an interactive map of Sears kit homes using the Folium package

In [1]:
# Load libraries
import folium
from folium import plugins
import ipywidgets
import geopy
import numpy as np
import pandas as pd
import geopandas as gpd
import json
/Users/mitchellfawcett/anaconda3/lib/python3.7/site-packages/pandas/compat/_optional.py:138: UserWarning: Pandas requires version '2.7.0' or newer of 'numexpr' (version '2.6.9' currently installed).
  warnings.warn(msg, UserWarning)
In [2]:
# Get list of Ohio kit home coordinates
# Read previously saved results on disk back to a dataframe
geocoded_results_df = pd.read_pickle('geocoded_results.pkl')

# Only keep rows that were successfully geocoded
geocoded_results_df = geocoded_results_df[geocoded_results_df["MATCH_INDICATOR"] == "Match"]

# Convert geography code values from numeric to string
geocoded_results_df['FIPS_STATE'] = geocoded_results_df['FIPS_STATE'].astype(int).astype(str)
geocoded_results_df['FIPS_COUNTY'] = geocoded_results_df['FIPS_COUNTY'].astype(int).astype(str)
geocoded_results_df['CENSUS_TRACT'] = geocoded_results_df['CENSUS_TRACT'].astype(int).astype(str)

# Left pad geograpgy values wit zeros
geocoded_results_df['FIPS_STATE'] = geocoded_results_df['FIPS_STATE'].apply('{:0>2}'.format)
geocoded_results_df['FIPS_COUNTY'] = geocoded_results_df['FIPS_COUNTY'].apply('{:0>3}'.format)
geocoded_results_df['CENSUS_TRACT'] = geocoded_results_df['CENSUS_TRACT'].apply('{:0>6}'.format)


# Create a unique geographic identifier by combining state, county and cenus tract code for each row.
geocoded_results_df["GeoID"] = geocoded_results_df["FIPS_STATE"] \
                                + geocoded_results_df["FIPS_COUNTY"] \
                                + geocoded_results_df["CENSUS_TRACT"]
                                
# Split the LONG_LAT column into separate Longitude and Latitude columns
geocoded_results_df[['Longitude', 'Latitude']] = geocoded_results_df['LONG_LAT'].str.rsplit(',', 1, expand=True)

geocoded_results_df.head()
Out[2]:
ID ADDRESS_IN MATCH_INDICATOR MATCH_TYPE ADDRESS_OUT LONG_LAT TIGER_EDGE STREET_SIDE FIPS_STATE FIPS_COUNTY CENSUS_TRACT CENSUS_BLOCK Zipcode GeoID Longitude Latitude
0 2 105 Meadow Brook Dr, Clarks Summit, PA, Match Exact 105 MEADOW BROOK DR, CLARKS SUMMIT, PA, 18411 -75.71287,41.500095 139319156.0 R 42 069 110402 2006.0 18411 42069110402 -75.71287 41.500095
2 4 541 Pine St, Ketchikan, AK, Match Exact 541 PINE ST, KETCHIKAN, AK, 99901 -131.64699,55.344284 207096132.0 L 02 130 000300 2000.0 99901 02130000300 -131.64699 55.344284
3 5 303 E Samford Ave, Auburn, AL, Match Exact 303 E SAMFORD AVE, AUBURN, AL, 36830 -85.47823,32.59884 1569988.0 L 01 081 040300 2008.0 36830 01081040300 -85.47823 32.59884
4 6 608 Brummel Ave, Bridgeport, AL, Match Exact 608 BRUMMEL AVE, BRIDGEPORT, AL, 35740 -85.7156,34.947346 58044064.0 R 01 071 950200 1062.0 35740 01071950200 -85.7156 34.947346
5 7 708 2nd St SE, Cullman, AL, Match Exact 708 2ND ST SE, CULLMAN, AL, 35055 -86.83624,34.17931 130220321.0 R 01 043 964901 4032.0 35055 01043964901 -86.83624 34.17931
In [3]:
# Build a list containing all the coordinates so they be plotted on the map
locations = geocoded_results_df[['Latitude', 'Longitude']]
locationlist = locations.values.tolist()
len(locationlist)

# An example of one point in the kit home location list
locationlist[7]
Out[3]:
['34.765038', '-87.70327']
In [4]:
# map with location start point, zoom level, size, and distance scale
# zoom in by using a larger number for zoom_start

# Center of Ohio 40.367474, -82.996216


Ohio_map = folium.Map(location=[40.367474, -82.996216], zoom_start=7, width=900, height=550, control_scale=True)
Ohio_map
Out[4]:
Make this Notebook Trusted to load map: File -> Trust Notebook

Regardless of the coordinate system of the actual map displayed, all coordinates passed to Leaflet functions/methods are always EPSG:4326.

To see what styles (weight, color,opacity etc.) can be applied to features in a layer, see https://leafletjs.com/reference-1.0.3.html#path

In [38]:
# map with location start point, zoom level, size, and distance scale
# Center of Ohio 40.367474, -82.996216

Ohio_map = folium.Map(location=[40.367474, -82.996216], zoom_start=7, width=900, height=550, control_scale=True)
# Ohio_map

marker_cluster = plugins.MarkerCluster().add_to(Ohio_map)  # 

# Define a function that can be called when a geojson layer file is added that modifies its appearance.
def stateOutline_style(feature):
    return {
        "weight": 5,
        "color": "#CB8427",
        "fill": False,
        "dashArray": '10,20'
    }

# Add a layer showing the outline of Ohio using the style function defined above.
# folium.GeoJson('Ohio Outline.geojson', name='Ohio outline', style_function = stateOutline_style).add_to(Ohio_map)

# Define a function that can be called when a geojson layer file is added that modifies its appearance.
def railDistance_style(feature):
    return {
        "weight": 2,
        "color": "red",
    }

# Add geojson file proximity to railroad to map 
# folium.GeoJson('Distance to Rail.geojson', name='Nearest Railroad', style_function = railDistance_style).add_to(Ohio_map)

# Define a function that can be called when a geojson layer file is added that modifies its appearance.
def censusTract_style(feature):
    return {
        "weight": 1,
        "color": "red",
        "fill": False,
    }

# Add geojson file census tracts to map using the style function defined above.
# folium.GeoJson('Ohio Census Tracts.geojson', name='Ohio Census Tracts', style_function = censusTract_style).add_to(Ohio_map)

# Add kit home location markers
for point in range(0, len(locationlist)):
    try:
        folium.CircleMarker(
            location = locationlist[point], 
            radius = 4,
            weight = 2,
            color = "red",
            fill = True,
            fill_color = "white",
            fill_opacity = 1.0
            # popup=mapping_data_df['Model'][point] + ": " + mapping_data_df['ADDRESS_OUT'][point],
        ).add_to(marker_cluster)

    except Exception:  # not all addresses could be geocoded so skip them if coordinates are missing
        pass



# add layer control to map (allows layer to be turned on or off)
# folium.LayerControl().add_to(Ohio_map)


# display map
# Ohio_map

Chloropleth map of structure age

Color code the Census Tracts according to the percent of structures built in 1939 and earlier. Cite https://towardsdatascience.com/how-to-step-up-your-folium-choropleth-map-skills-17cf6de7c6fe

In [9]:
# Load structure age data generated by this Notebook: Sears Kit Home Location Analysis 
tract_yearBuilt_df = pd.read_csv("tract_yearBuilt_df.csv")
In [30]:
tract_yearBuilt_df.head()
Out[30]:
Unnamed: 0 NAME Percent Built 1939 and Earlier state county tract GEOID
0 0 Census Tract 46.04, Hamilton County, Ohio 4.1 39 61 4604 39061004604
1 1 Census Tract 2104.02, Greene County, Ohio 0.9 39 57 210402 39057210402
2 2 Census Tract 2802, Greene County, Ohio 23.5 39 57 280200 39057280200
3 3 Census Tract 2803, Greene County, Ohio 35.9 39 57 280300 39057280300
4 4 Census Tract 46.05, Hamilton County, Ohio 7.8 39 61 4605 39061004605
In [31]:
# Find the values of Percent Built 1939 and Earlier, sorted, to look for problem values.
# Tract numbers like 99... and 98... are bodies of water or areas without countable population
tract_yearBuilt_df[tract_yearBuilt_df["Percent Built 1939 and Earlier"]< 0 ]
Out[31]:
Unnamed: 0 NAME Percent Built 1939 and Earlier state county tract GEOID
In [12]:
# Remove those rows
tract_yearBuilt_df = tract_yearBuilt_df[tract_yearBuilt_df["Percent Built 1939 and Earlier"] >= 0 ]
In [13]:
census_tract_geo_df = gpd.read_file("Ohio Census Tracts.geojson")
In [14]:
census_tract_geo_df
Out[14]:
STATEFP COUNTYFP TRACTCE GEOID NAME NAMELSAD MTFCC FUNCSTAT ALAND AWATER INTPTLAT INTPTLON geometry
0 39 021 010200 39021010200 102 Census Tract 102 G5020 S 254963980 1528641 +40.1538168 -083.9647388 MULTIPOLYGON (((-84.03607 40.04018, -84.03493 ...
1 39 021 010500 39021010500 105 Census Tract 105 G5020 S 6985049 4584 +40.1121978 -083.7257641 MULTIPOLYGON (((-83.76088 40.10866, -83.76041 ...
2 39 021 010400 39021010400 104 Census Tract 104 G5020 S 37288174 128056 +40.1384153 -083.7873623 MULTIPOLYGON (((-83.82511 40.12336, -83.82511 ...
3 39 085 204302 39085204302 2043.02 Census Tract 2043.02 G5020 S 4108020 11929 +41.7124067 -081.2575497 MULTIPOLYGON (((-81.27577 41.70526, -81.27574 ...
4 39 085 206600 39085206600 2066 Census Tract 2066 G5020 S 2637240 0 +41.6488658 -081.4558890 MULTIPOLYGON (((-81.46264 41.65285, -81.46222 ...
... ... ... ... ... ... ... ... ... ... ... ... ... ...
2947 39 085 201400 39085201400 2014 Census Tract 2014 G5020 S 3228184 101020 +41.6332723 -081.4091922 MULTIPOLYGON (((-81.41955 41.62933, -81.41949 ...
2948 39 085 201600 39085201600 2016 Census Tract 2016 G5020 S 3684132 64927 +41.6646235 -081.3957812 MULTIPOLYGON (((-81.42017 41.65348, -81.41821 ...
2949 39 085 201700 39085201700 2017 Census Tract 2017 G5020 S 4542739 0 +41.6886294 -081.3989244 MULTIPOLYGON (((-81.40994 41.67575, -81.40991 ...
2950 39 085 201800 39085201800 2018 Census Tract 2018 G5020 S 1921910 0 +41.6828441 -081.4160386 MULTIPOLYGON (((-81.42793 41.68215, -81.42729 ...
2951 39 085 201900 39085201900 2019 Census Tract 2019 G5020 S 3333914 197567 +41.6678196 -081.4146595 MULTIPOLYGON (((-81.43671 41.67677, -81.43656 ...

2952 rows × 13 columns

In [15]:
ct = list(census_tract_geo_df.GEOID.values)
print("Number of census tracts in the geojson file of boundaries is",len(ct))
Number of census tracts in the geojson file of boundaries is 2952
In [16]:
census_tract_geo_df.info()
<class 'geopandas.geodataframe.GeoDataFrame'>
RangeIndex: 2952 entries, 0 to 2951
Data columns (total 13 columns):
 #   Column    Non-Null Count  Dtype   
---  ------    --------------  -----   
 0   STATEFP   2952 non-null   object  
 1   COUNTYFP  2952 non-null   object  
 2   TRACTCE   2952 non-null   object  
 3   GEOID     2952 non-null   object  
 4   NAME      2952 non-null   object  
 5   NAMELSAD  2952 non-null   object  
 6   MTFCC     2952 non-null   object  
 7   FUNCSTAT  2952 non-null   object  
 8   ALAND     2952 non-null   int64   
 9   AWATER    2952 non-null   int64   
 10  INTPTLAT  2952 non-null   object  
 11  INTPTLON  2952 non-null   object  
 12  geometry  2952 non-null   geometry
dtypes: geometry(1), int64(2), object(10)
memory usage: 299.9+ KB
In [17]:
ct2 = list(tract_yearBuilt_df.GeoID.values)
print("Number of census tracts in the year structure built dataset is",len(ct2))
Number of census tracts in the year structure built dataset is 2938

Both counts are the same so no cleanup of missing census tracts is needed.

In [18]:
# Rename the geoid in one file to match the other
tract_yearBuilt_df = tract_yearBuilt_df.rename(columns = {"GeoID":"GEOID"})
In [19]:
tract_yearBuilt_df.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 2938 entries, 0 to 2951
Data columns (total 7 columns):
 #   Column                          Non-Null Count  Dtype  
---  ------                          --------------  -----  
 0   Unnamed: 0                      2938 non-null   int64  
 1   NAME                            2938 non-null   object 
 2   Percent Built 1939 and Earlier  2938 non-null   float64
 3   state                           2938 non-null   int64  
 4   county                          2938 non-null   int64  
 5   tract                           2938 non-null   int64  
 6   GEOID                           2938 non-null   int64  
dtypes: float64(1), int64(5), object(1)
memory usage: 183.6+ KB
In [20]:
# Convert the GEOID column to an object type
tract_yearBuilt_df = tract_yearBuilt_df.astype({"GEOID": str})
In [21]:
final_df = tract_yearBuilt_df.merge(census_tract_geo_df, on = "GEOID")
final_df.head()
Out[21]:
Unnamed: 0 NAME_x Percent Built 1939 and Earlier state county tract GEOID STATEFP COUNTYFP TRACTCE NAME_y NAMELSAD MTFCC FUNCSTAT ALAND AWATER INTPTLAT INTPTLON geometry
0 0 Census Tract 46.04, Hamilton County, Ohio 4.1 39 61 4604 39061004604 39 061 004604 46.04 Census Tract 46.04 G5020 S 2770730 717 +39.1024958 -084.3841195 MULTIPOLYGON (((-84.39987 39.10856, -84.39980 ...
1 1 Census Tract 2104.02, Greene County, Ohio 0.9 39 57 210402 39057210402 39 057 210402 2104.02 Census Tract 2104.02 G5020 S 6958239 5794 +39.7043590 -084.0850890 MULTIPOLYGON (((-84.10597 39.69734, -84.10596 ...
2 2 Census Tract 2802, Greene County, Ohio 23.5 39 57 280200 39057280200 39 057 280200 2802 Census Tract 2802 G5020 S 64665875 368100 +39.7971649 -083.8740350 MULTIPOLYGON (((-83.94546 39.78943, -83.94523 ...
3 3 Census Tract 2803, Greene County, Ohio 35.9 39 57 280300 39057280300 39 057 280300 2803 Census Tract 2803 G5020 S 26875803 710497 +39.8218883 -084.0499346 MULTIPOLYGON (((-84.08607 39.81090, -84.08566 ...
4 4 Census Tract 46.05, Hamilton County, Ohio 7.8 39 61 4605 39061004605 39 061 004605 46.05 Census Tract 46.05 G5020 S 4575494 135122 +39.0968292 -084.4033598 MULTIPOLYGON (((-84.42136 39.08551, -84.42046 ...
In [22]:
folium.Choropleth?
In [23]:
with open('Ohio Census Tracts.geojson') as f:
    geojson_censustracts = json.load(f)
In [24]:
geojson_censustracts["features"][0]
Out[24]:
{'type': 'Feature',
 'properties': {'STATEFP': '39',
  'COUNTYFP': '021',
  'TRACTCE': '010200',
  'GEOID': '39021010200',
  'NAME': '102',
  'NAMELSAD': 'Census Tract 102',
  'MTFCC': 'G5020',
  'FUNCSTAT': 'S',
  'ALAND': 254963980,
  'AWATER': 1528641,
  'INTPTLAT': '+40.1538168',
  'INTPTLON': '-083.9647388'},
 'geometry': {'type': 'MultiPolygon',
  'coordinates': [[[[-84.036069, 40.040182],
     [-84.034933, 40.053404],
     [-84.034731, 40.055759],
     [-84.034684, 40.056151],
     [-84.034075, 40.061278],
     [-84.034075, 40.061294],
     [-84.033996, 40.062209],
     [-84.033608, 40.066719],
     [-84.033298, 40.070384],
     [-84.032989, 40.073927],
     [-84.032655, 40.077773],
     [-84.032336, 40.082163],
     [-84.031937, 40.086032],
     [-84.031935, 40.086072],
     [-84.031569, 40.090407],
     [-84.029862, 40.111361],
     [-84.029857, 40.111431],
     [-84.029521, 40.115128],
     [-84.028618, 40.125054],
     [-84.02856, 40.125694],
     [-84.028561, 40.125803],
     [-84.028561, 40.125815],
     [-84.028561, 40.125854],
     [-84.028562, 40.125867],
     [-84.028556, 40.125932],
     [-84.028522, 40.126266],
     [-84.028404, 40.127463],
     [-84.028365, 40.127862],
     [-84.028288, 40.128706],
     [-84.028061, 40.131241],
     [-84.027985, 40.132086],
     [-84.027283, 40.13565],
     [-84.027241, 40.140198],
     [-84.027238, 40.140233],
     [-84.026072, 40.15152],
     [-84.025837, 40.154716],
     [-84.02583, 40.154782],
     [-84.02424, 40.167887],
     [-84.024237, 40.167926],
     [-84.023778, 40.173182],
     [-84.022919, 40.183945],
     [-84.022898, 40.183988],
     [-84.021659, 40.197475],
     [-84.021568, 40.198444],
     [-84.021392, 40.20061],
     [-84.021316, 40.201755],
     [-84.021102, 40.203884],
     [-84.020843, 40.20716],
     [-84.020713, 40.209228],
     [-84.020591, 40.210193],
     [-84.020538, 40.21109],
     [-84.020378, 40.212142],
     [-84.019889, 40.217231],
     [-84.019836, 40.218029],
     [-84.019851, 40.21809],
     [-84.019882, 40.21812],
     [-84.019218, 40.224494],
     [-84.018989, 40.227649],
     [-84.018936, 40.228187],
     [-84.018852, 40.229549],
     [-84.018783, 40.230118],
     [-84.01878, 40.230139],
     [-84.018356, 40.234523],
     [-84.017723, 40.242076],
     [-84.017639, 40.242176],
     [-84.017456, 40.244144],
     [-84.017453, 40.24416],
     [-84.017234, 40.246532],
     [-84.017059, 40.248497],
     [-84.016937, 40.249691],
     [-84.016815, 40.250869],
     [-84.016754, 40.251567],
     [-84.016731, 40.251838],
     [-84.016296, 40.256626],
     [-84.015632, 40.263927],
     [-84.014938, 40.271354],
     [-84.014763, 40.273459],
     [-84.014608, 40.273446],
     [-84.008039, 40.273066],
     [-84.004018, 40.272821],
     [-83.998627, 40.272503],
     [-83.993361, 40.272187],
     [-83.992637, 40.272141],
     [-83.984578, 40.271579],
     [-83.983364, 40.271499],
     [-83.982785, 40.271461],
     [-83.981012, 40.27136],
     [-83.976364, 40.271095],
     [-83.974289, 40.270985],
     [-83.965829, 40.2705],
     [-83.965124, 40.270461],
     [-83.964682, 40.270436],
     [-83.962899, 40.270337],
     [-83.961436, 40.270243],
     [-83.955565, 40.269887],
     [-83.955342, 40.269873],
     [-83.926709, 40.268271],
     [-83.926642, 40.268268],
     [-83.926615, 40.268267],
     [-83.915407, 40.26758],
     [-83.909359, 40.26721],
     [-83.907716, 40.267107],
     [-83.905753, 40.266991],
     [-83.900122, 40.266647],
     [-83.898367, 40.266545],
     [-83.898513, 40.265083],
     [-83.898872, 40.261491],
     [-83.898948, 40.260699],
     [-83.89909, 40.259238],
     [-83.900015, 40.250053],
     [-83.899995, 40.247428],
     [-83.900063, 40.246714],
     [-83.900389, 40.243362],
     [-83.901371, 40.233309],
     [-83.901699, 40.229958],
     [-83.901968, 40.227068],
     [-83.902778, 40.2184],
     [-83.903048, 40.215511],
     [-83.903138, 40.214605],
     [-83.903411, 40.211888],
     [-83.903502, 40.210983],
     [-83.903553, 40.210446],
     [-83.903708, 40.208835],
     [-83.90376, 40.208299],
     [-83.903937, 40.206844],
     [-83.904472, 40.202482],
     [-83.90465, 40.201029],
     [-83.904717, 40.200243],
     [-83.904789, 40.1994],
     [-83.90493, 40.197887],
     [-83.904989, 40.197256],
     [-83.905004, 40.197103],
     [-83.90507, 40.196436],
     [-83.905203, 40.195111],
     [-83.905265, 40.194436],
     [-83.905327, 40.19377],
     [-83.905391, 40.193069],
     [-83.9054, 40.192983],
     [-83.905604, 40.190969],
     [-83.905676, 40.19027],
     [-83.905682, 40.190206],
     [-83.905701, 40.190015],
     [-83.905708, 40.189952],
     [-83.905773, 40.189301],
     [-83.90597, 40.18735],
     [-83.906036, 40.1867],
     [-83.906074, 40.18632],
     [-83.906134, 40.185722],
     [-83.906192, 40.185183],
     [-83.906234, 40.184804],
     [-83.906293, 40.184257],
     [-83.906472, 40.182619],
     [-83.906493, 40.182428],
     [-83.906526, 40.182073],
     [-83.906557, 40.181741],
     [-83.906638, 40.180896],
     [-83.906655, 40.180749],
     [-83.906694, 40.180419],
     [-83.906718, 40.180209],
     [-83.90672, 40.180193],
     [-83.906785, 40.179959],
     [-83.90692, 40.179624],
     [-83.906925, 40.179614],
     [-83.907023, 40.179428],
     [-83.907284, 40.176293],
     [-83.908067, 40.166888],
     [-83.908329, 40.163754],
     [-83.908465, 40.162526],
     [-83.908874, 40.158841],
     [-83.909011, 40.157614],
     [-83.909139, 40.156264],
     [-83.909523, 40.152215],
     [-83.909652, 40.150866],
     [-83.909695, 40.150559],
     [-83.909823, 40.149639],
     [-83.909867, 40.149333],
     [-83.909989, 40.148128],
     [-83.910357, 40.144513],
     [-83.91048, 40.143309],
     [-83.910498, 40.143125],
     [-83.910555, 40.142572],
     [-83.910574, 40.142389],
     [-83.910681, 40.141374],
     [-83.911003, 40.138329],
     [-83.911111, 40.137315],
     [-83.911142, 40.137016],
     [-83.911236, 40.136118],
     [-83.911268, 40.13582],
     [-83.911312, 40.135316],
     [-83.911461, 40.133987],
     [-83.911709, 40.131476],
     [-83.912344, 40.125056],
     [-83.912443, 40.123942],
     [-83.912669, 40.121429],
     [-83.912672, 40.121327],
     [-83.912682, 40.121021],
     [-83.912686, 40.12092],
     [-83.912702, 40.120664],
     [-83.912876, 40.118954],
     [-83.913477, 40.11306],
     [-83.913678, 40.111096],
     [-83.913761, 40.110224],
     [-83.914013, 40.107607],
     [-83.914097, 40.106736],
     [-83.914343, 40.103605],
     [-83.915081, 40.094215],
     [-83.915328, 40.091085],
     [-83.91556, 40.088399],
     [-83.916258, 40.080342],
     [-83.916491, 40.077657],
     [-83.9169, 40.073615],
     [-83.918129, 40.061489],
     [-83.91854, 40.057448],
     [-83.918547, 40.057434],
     [-83.918571, 40.057328],
     [-83.918589, 40.057252],
     [-83.918612, 40.056958],
     [-83.918623, 40.056835],
     [-83.918631, 40.056732],
     [-83.91864, 40.05664],
     [-83.918665, 40.056425],
     [-83.918678, 40.056323],
     [-83.918738, 40.055825],
     [-83.918814, 40.055216],
     [-83.918839, 40.054879],
     [-83.918849, 40.054756],
     [-83.918853, 40.054703],
     [-83.918855, 40.054683],
     [-83.918862, 40.054432],
     [-83.918881, 40.054145],
     [-83.918946, 40.053657],
     [-83.918992, 40.053309],
     [-83.919075, 40.052677],
     [-83.919103, 40.052387],
     [-83.919267, 40.050734],
     [-83.919338, 40.050044],
     [-83.919383, 40.049615],
     [-83.919386, 40.049588],
     [-83.919464, 40.048691],
     [-83.919473, 40.048593],
     [-83.9195, 40.0483],
     [-83.91951, 40.048203],
     [-83.919538, 40.047902],
     [-83.919689, 40.04641],
     [-83.919731, 40.045997],
     [-83.919753, 40.045782],
     [-83.919841, 40.044924],
     [-83.919993, 40.043466],
     [-83.92014, 40.041991],
     [-83.920254, 40.041037],
     [-83.920427, 40.039385],
     [-83.920556, 40.038168],
     [-83.920645, 40.03718],
     [-83.920704, 40.036442],
     [-83.920715, 40.036343],
     [-83.920842, 40.035114],
     [-83.920886, 40.034586],
     [-83.920915, 40.034367],
     [-83.920967, 40.034149],
     [-83.921005, 40.034058],
     [-83.939563, 40.034945],
     [-83.939855, 40.034959],
     [-83.941418, 40.035107],
     [-83.944126, 40.035366],
     [-83.944353, 40.035387],
     [-83.969595, 40.036853],
     [-83.971342, 40.036954],
     [-83.978472, 40.03746],
     [-83.978801, 40.037482],
     [-83.979907, 40.037551],
     [-83.984026, 40.037807],
     [-83.98406, 40.037809],
     [-83.984098, 40.037811],
     [-83.984214, 40.037818],
     [-83.984253, 40.037821],
     [-83.984463, 40.037834],
     [-83.986904, 40.038013],
     [-83.996418, 40.038423],
     [-83.998375, 40.03835],
     [-83.999935, 40.038267],
     [-84.000197, 40.038281],
     [-84.000982, 40.038325],
     [-84.001245, 40.03834],
     [-84.018323, 40.039122],
     [-84.01874, 40.039154],
     [-84.021522, 40.039312],
     [-84.027393, 40.039647],
     [-84.02958, 40.039837],
     [-84.030135, 40.039855],
     [-84.033401, 40.040034],
     [-84.035221, 40.040139],
     [-84.035832, 40.040182],
     [-84.036038, 40.04019],
     [-84.036069, 40.040182]]]]}}
In [34]:
# om = folium.Map(location=[40.367474, -82.996216], zoom_start=7, width=900, height=550, control_scale=True)
In [39]:
# Set the parameters for the Choropleth

# Folium allows a number of formats for the "geo_data" parameter.  It can be the name of a geojson file
# on local disk, a URL to a file on the Web, or the name of a pandas dataframe in memory that has been loaded 
# with a geojson file. The disk file or URL names need to be surrounded by quote marks.  The dataframe 
# name does not need quote marks.

# Regardless of which format of "geo_data" used, the "key_on" parameter must be of the form 
# "feature.id" or "feature.properties.<a column name>".  I used the second format here because I used
# the dataframe method of passing the geo_data value. If I had used a json file name or URL path 
# in the geo_data parameter I would have had to add an "id" feature to the json data, similar to the following:

# for i in geojson_data['features']:
#    i['id'] = i['properties']['NAME'] # 'NAME' being a column of unique values in the json

folium.Choropleth(
    geo_data=census_tract_geo_df,
    name="choropleth",
    data=final_df,
    columns=["GEOID", "Percent Built 1939 and Earlier"],
    key_on='feature.properties.GEOID',
    fill_color='YlGn',
    fill_opacity=0.5,
    line_opacity=0.5,
    legend_name='Structure age',
    highlight=True

).add_to(Ohio_map)


# add layer control to map (allows layer to be turned on or off)
folium.LayerControl().add_to(Ohio_map)


Ohio_map
Out[39]:
Make this Notebook Trusted to load map: File -> Trust Notebook
In [40]:
Ohio_map.save("ohio_map.html")
In [ ]: